//---------------------------------------------------------------------------------
#include <nds.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fat.h>

#include "poker_eval.h"
#include "screen.h"
#include "wifi.h"

#define BET_TIME 10
#define TIME_BANK 20

int blinds[] = {20, 30, 40, 50, 60, 80, 100, 120, 160, 200, 240, 280, 340, 400, 500, 600, 800, 1000, 1200, 1600, 2000, 2400, 2800, 3400, 4000};

int Deck[52];
char *PlayerNames[MAX_PLAYERS];
int CRCs[MAX_PLAYERS];

int ThisPlayer;
int MinsPerLevel;
int ThisDS;
int NumCards;
GameMode Mode;

char CommunityCards[32];

GAME Game;
char PlayerName[MAX_NAME_LEN];
bool HoleCardsShowing;
bool CheckFold;
bool SitOut;
bool ShowingReplay;

const int MAX_OLD_HANDS = 5;
char OldHands[MAX_OLD_HANDS][24 * 32 * 2];
int OldHandPtr;

extern u16* subMap;
extern u16* subMap2;
extern int bg0, bg1;
extern bool Inverse;
extern struct SEAT EightSeats[MAX_PLAYERS];
extern struct SEAT SixSeats[MAX_PLAYERS];
extern struct SEAT *Seats;
extern double Results[8];

#define ICON_RAISED 227
#define ICON_CALLED 228
#define ICON_CHECKED 229
#define ICON_FOLDED 230


/*
TODO:
-----
o Make it possible to uncheck SitOut at any time.
o Flash mucked cards during/after showdown.
o Game ID for multiple concurrent games?
o Re-enable load/save when we all have DS cards that can save.
o Weird bug on Fred's DS where it showed last hand plus next hand.
o Add random timer to stop play after ~1 hour.
o When watching two players, the DS that was watching displayed "Click to start hand" message.

*/

int NextCard(int& DeckPos)
{
    return Deck[DeckPos++];
}

int CountPlayers(bool includeRebuys = false)
{
    int f;
    int totPlayers = 0;

    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        if(Game.Players[f].Chips > 0)
        {
            totPlayers++;
        }
        else if(includeRebuys && Game.Players[f].SitOutHands > 0)
        {
            totPlayers++;
        }
    }
    return totPlayers;
}

void RaiseBlinds(void)
{
    Game.LevelStartTime += SECS_PER_MIN * MinsPerLevel;

    unsigned int f;

    // Find current blind in list, move to next.
    for(f = 0 ; f < (sizeof(blinds) / sizeof(int)) - 1; f++)
    {
        if(blinds[f] == Game.Blind)
        {
            Game.Blind = blinds[f + 1];
            break;
        }
    }
}

void MoveButton(void)
{
    while(1)
    {
        Game.ButtonPos = (Game.ButtonPos + 1) % Game.MaxPlayers;
        if(Game.Players[Game.ButtonPos].Chips > 0)
        {
            break;
        }
    }
}

void NextPlayer(void)
{
    bool highlightPlayer = true;

    int f;
    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        DisplayPlayer(f, false);
    }

    while(1)
    {
        Game.ActionOnPlayer = (Game.ActionOnPlayer + 1) % Game.MaxPlayers;

        if(Game.Players[Game.ActionOnPlayer].Chips == 0)
        {
            if(Game.ActionOnPlayer == Game.LastToAct)
            {
                highlightPlayer = false;
                break;
            }
            // Player is all-in.  Move to next player.
            continue;
        }
        if(Game.Players[Game.ActionOnPlayer].Folded)
        {
            // Player has folded.  Move to next player.
            continue;
        }
        break;
    }
    DisplayPlayer(Game.ActionOnPlayer, highlightPlayer);

    if(Mode == gm_Standalone)
    {
        ThisPlayer = Game.ActionOnPlayer;
        DisplayHoleCards(Game.ActionOnPlayer);
    }
}

int FindLastToAct(int player)
{
    int origPlayer = player;
    do
    {
        player--;
        if(player == -1)
        {
            player = Game.MaxPlayers - 1;
        }
        if(player == origPlayer)
        {
            break;
        }
    }
    while(Game.Players[player].Folded || Game.Players[player].Chips == 0);

    return player;
}

void Fold(int player, bool showDown = false)
{
    Game.Players[player].Folded = true;
    Game.Players[player].Action = ' ';

    DisplayPlayer(player, false);
    DisplayCards(player, false);

    if(player == ThisPlayer && Mode != gm_Standalone && !showDown)
    {
        DisplayHoleCards(player);
        ClearRows(BOTTOM, 7, 19);
    }
}

inline int AllInCount(int player)
{
    return Game.Players[player].Chips + Game.Players[player].Bet;
}

bool ConfirmBet(int bet, int player)
{
    bool valid = false;
    bool raised = false;
    int totBet = bet;

    // A valid bet is the minimum bet, a raise that at least doubles the
    // last raise (or bet), or an all-in.
    if(!Game.LastRaise)
    {
        if(totBet >= Game.MinBet)
        {
            valid = true;
            raised = true;
            Game.LastRaise = bet;
            Game.MinBet = totBet;
        }
        else if(bet == AllInCount(player))
        {
            // All In.
            valid = true;
            raised = true;
            Game.MinBet = bet;
            Game.LastRaise = Game.Blind;
            // TODO: What's the LastRaise?
        }
    }
    else
    {
        if(totBet == Game.MinBet)
        {
            valid = true;
        }
        else if(totBet >= Game.MinBet + Game.LastRaise)
        {
            valid = true;
            raised = true;
            Game.LastRaise = totBet - Game.MinBet;
            Game.MinBet = totBet;
        }
        else if(bet == AllInCount(player))
        {
            // All In.
            valid = true;
            if(bet > Game.MinBet)
            {
                raised = true;
                Game.MinBet = bet;
                // TODO: What's the LastRaise?
            }
        }
    }

    if(valid)
    {
        Game.Players[player].Chips -= bet - Game.Players[player].Bet;
        Game.Pot += bet - Game.Players[player].Bet;
        DisplayPot();

        Game.Players[player].Bet = totBet;
        DisplayBet(player, totBet);
    }

    if(raised)
    {
        // Someone raised.  Nobody can check now.
        int f;

        for(f = 0 ; f < Game.MaxPlayers ; f++)
        {
            Game.Players[f].CanCheck = false;
        }
        Game.Raiser = player;
        Game.LastToAct = FindLastToAct(player);
        Game.Players[player].Action = ICON_RAISED;
    }
    else
    {
        Game.Players[player].Action = ICON_CALLED;
    }
    return valid;
}

Button ConvertTouchToButton(int pressed, touchPosition& touch, bool& repeat)
{
    int keysRepeat = keysDownRepeat();

    repeat = false;
    if(!pressed)
    {
        if(keysRepeat & KEY_X)
        {
            repeat = true;
            return btn_AllIn;
        }
        else
        {
            if(keysRepeat == KEY_UP || keysRepeat == KEY_DOWN)
            {
                pressed = keysRepeat;
            }
        }
    }

    if(pressed & KEY_SELECT)
    {
        return btn_Select;
    }

    if(pressed & KEY_L)
    {
        return btn_LeftShoulder;
    }

    if(pressed & KEY_R)
    {
        return btn_RightShoulder;
    }

    if(pressed & KEY_UP)
    {
        return btn_Plus;
    }

    if(pressed & KEY_DOWN)
    {
        return btn_Minus;
    }

    if(pressed & KEY_LEFT)
    {
        return btn_Replay;
    }

    if(pressed & KEY_RIGHT)
    {
        return btn_HoleCards;
    }

    if(pressed & KEY_A)
    {
        return btn_CheckCall;
    }

    if(pressed & KEY_X)
    {
        return btn_BetRaise;
    }

    if(pressed & KEY_B)
    {
        return btn_Fold;
    }

    if(pressed & KEY_Y)
    {
        return btn_23Pot;
    }

    if(pressed & KEY_TOUCH)
    {
        if(touch.px >= 0 && touch.px <= 15 && touch.py >= 33 && touch.py <= 46)
        {
            return btn_Replay;
        }

        if(touch.px >= 24 && touch.px <=80 && touch.py >= 32 && touch.py <= (32 + 8 * NumCards))
        {
            return btn_HoleCards;
        }

        if(touch.px >= 2 && touch.px <= 44 && touch.py >= 128 && touch.py <= 143)
        {
            return btn_Fold;
        }

        if(touch.px >= 2 && touch.px <= 18 && touch.py >= 152 && touch.py <= 168)
        {
            return btn_Rabbit;
        }

        if(touch.px >= 2 && touch.px <= 37 && touch.py >= 56 && touch.py <= 71)
        {
            return btn_SitOut;
        }

        if(touch.px >= 98 && touch.px <= 140)
        {
            // Left row of buttons: CALL/CHECK, BET/RAISE, ALLIN
            if(touch.py >= 80 && touch.py <= 96)
            {
                return btn_CheckCall;
            }
            if(touch.py >= 104 && touch.py <= 119)
            {
                return btn_BetRaise;
            }
            if(touch.py >= 128 && touch.py <= 143)
            {
                return btn_AllIn;
            }
        }

        if(touch.px >= 210 && touch.px <= 252)
        {
            // Right row of buttons: 2/3 POT, 3/4 POT, POT
            if(touch.py >= 80 && touch.py <= 96)
            {
                return btn_23Pot;
            }
            else if(touch.py >= 104 && touch.py <= 119)
            {
                return btn_34Pot;
            }
            else if(touch.py >= 128 && touch.py <= 143)
            {
                return btn_Pot;
            }
            // Also QUIT button in Standalone mode.
            else if(touch.py >= 56 && touch.py <= 72)
            {
                return btn_Quit;
            }
        }

        if(touch.px >= 151 && touch.px <= 200 && touch.py >= 64 && touch.py <= 77)
        {
            return btn_Confirm;
        }

        if(touch.px >= 152 && touch.px <= 199 && touch.py >= 80 && touch.py <= 144)
        {
            return btn_NumPad;
        }

        if(touch.py >= 154 && touch.py <= 166)
        {
            if(touch.px >= 98 && touch.px <= 109)
            {
                return btn_Minus;
            }

            if(touch.px >= 241 && touch.px <= 252)
            {
                return btn_Plus;
            }
        }

        return btn_Any;
    }

    return btn_None;
}

void SwitchSitOut(void)
{
    if(Mode != gm_Standalone)
    {
        SitOut = !SitOut;

        CheckFold = SitOut;
        DisplayCheckBox(BOTTOM, 5, 7, SitOut);

        if(!Game.Players[ThisPlayer].Folded)
        {
            if(Game.State == gs_PreFlopBetting || Game.State == gs_PostFlopBetting ||
               Game.State == gs_PostTurnBetting || Game.State == gs_PostRiverBetting)
            {
                DisplayCheckBox(BOTTOM, 6, 16, CheckFold);
                DisplayHoleCards(ThisPlayer);
            }
        }
    }
}

void ShowReplay(bool show)
{
    static int handShowing;
    // Move further back
    if(ShowingReplay && show)
    {
        handShowing--;
        if(handShowing == -1)
        {
            handShowing = MAX_OLD_HANDS - 1;
        }
        dmaCopy(OldHands[handShowing], subMap2, 24 * 32 * 2);
    }
    else
    {
        ShowingReplay = show;
        if(show)
        {
            handShowing = OldHandPtr - 1;
            if(handShowing == -1)
            {
                handShowing = MAX_OLD_HANDS - 1;
            }
            dmaCopy(OldHands[handShowing], subMap2, 24 * 32 * 2);
            bgHide(bg0);
            bgShow(bg1);
        }
        else
        {
            bgHide(bg1);
            bgShow(bg0);
        }
    }
}

bool ConvertTouchToBet(int player, int& CurrentBet)
{
    static int KeypadValues[] = {7,8,9,4,5,6,1,2,3,0,-1,-2};
    static int bright = 0;
    static touchPosition touch;

    bool canComplete = (player == Game.ActionOnPlayer);
    bool betComplete = false;
    bool confirm = false;
    int newBet = CurrentBet;
    int value;
    int x, y;
    int temp;
    bool repeat;

    int pressed = KeyPressed(&touch);
    Button b = ConvertTouchToButton(pressed, touch, repeat);
//prints(BOTTOM, 10, 2, "%04i, %04i", touch.px, touch.py);

    if(b == btn_Select)
    {
        u16 temp;

        // +15 is background, +0 is foreground.
        temp = *(BG_PALETTE + 0);
        *(BG_PALETTE + 0) = *(BG_PALETTE + 15);
        *(BG_PALETTE + 15) = temp;

        *(BG_PALETTE_SUB + 0) = *(BG_PALETTE_SUB + 15);
        *(BG_PALETTE_SUB + 15) = temp;

        if(*(BG_PALETTE + 16 + 15) == YELLOW)
        {
            *(BG_PALETTE + 16 + 15) = *(BG_PALETTE_SUB + 16 + 15) = BLUE;
        }
        else
        {
            *(BG_PALETTE + 16 + 15) = *(BG_PALETTE_SUB + 16 + 15) = YELLOW;
        }
    }
    else if(b == btn_LeftShoulder)
    {
        bright-=4;
        if(bright < -12)
        {
            bright = 12;
        }
        setBrightness(3, bright);
    }
    else if(b == btn_RightShoulder)
    {
        bright+=4;
        if(bright >= 12)
        {
            bright = -12;
        }
        setBrightness(3, bright);
    }

    // Return to betting screen from last hand summary.  Either because user touched screen
    // or action is on user.
    if(ShowingReplay && (b != btn_None || (canComplete && Mode != gm_Standalone)))
    {
        if(b == btn_Replay)
        {
            ShowReplay(true);
        }
        else
        {
            ShowReplay(false);
        }
        return false;
    }

    // Show last hand summary.
    if(b == btn_Replay && !ShowingReplay && (!canComplete || Mode == gm_Standalone))
    {
        ShowReplay(true);
        return false;
    }

    if(b == btn_HoleCards)
    {
        // Hide/show hole cards.
        HoleCardsShowing = !HoleCardsShowing;
        DisplayHoleCards(player);
    }

    if(Game.Players[player].Folded)
    {
        return false;
    }

    // Slider bar operates using continuous sensing.
    if(touch.px >= 110 && touch.px <= 240 && touch.py >= 154 && touch.py <= 166)
    {
        newBet = (AllInCount(player)) * ((touch.px - 105) / 8) / 16;
        newBet = newBet - (newBet % 10);
    }
    else
    {
        if(canComplete)
        {
            switch(b)
            {
            case btn_Quit:
                if(Mode == gm_Standalone)
                {
                    // QUIT
                    Game.State = gs_Complete;
                    return false;
                }
                break;

            case btn_Fold:
                // FOLD
                newBet = 0;
                Fold(ThisPlayer);
                if(Game.Players[ThisPlayer].CanCheck)
                {
                    Game.Players[ThisPlayer].Action = ICON_FOLDED;
                }
                betComplete = true;
                break;

            case btn_Rabbit:
                if(CanHunt(player))
                {
                    // Rabbit Hunt
                    newBet = 0;
                    Fold(ThisPlayer);
                    betComplete = true;
                    Game.RabbitHunt = true;
                    Game.Players[player].RabbitHunts--;
                }
                break;

            case btn_CheckCall:
                if(!Game.Players[player].CanCheck)
                {
                    // CALL
                    if(CurrentBet == Game.MinBet || (CurrentBet == AllInCount(player) && Game.MinBet >= AllInCount(player)))
                    {
                        confirm = true;
                    }
                    else
                    {
                        if(Game.MinBet < AllInCount(player))
                        {
                            newBet = Game.MinBet;
                        }
                        else
                        {
                            newBet = AllInCount(player);
                        }
                    }
                }
                else
                {
                    // CHECK
                    betComplete = canComplete;
                    if(betComplete)
                    {
                        Game.Players[player].Action = ICON_CHECKED;
                    }
                }
                break;

            case btn_BetRaise:
                if(Game.LastRaise == 0)
                {
                    // BET
                    if(CurrentBet >= Game.MinBet)
                    {
                        confirm = true;
                    }
                    else
                    {
                        newBet = Game.MinBet;
                    }
                }
                else
                {
                    // RAISE
                    if(CurrentBet >= Game.MinBet + Game.LastRaise || CurrentBet == AllInCount(player))
                    {
                        confirm = true;
                    }
                    else
                    {
                        newBet = Game.MinBet + Game.LastRaise;
                    }
                }
                break;

            case btn_AllIn:
                // ALLIN
                if(CurrentBet == AllInCount(player))
                {
                    if(!repeat)
                    {
                        confirm = true;
                    }
                }
                else
                {
                    newBet = AllInCount(player);
                }
                break;

            case btn_23Pot:
                // 2/3 POT, rounded to a multiple of 10
                temp = Game.Pot * 2 / 3;
                temp = temp - (temp % 10);
                if(CurrentBet == temp)
                {
                    confirm = true;
                }
                else
                {
                    newBet = temp;
                }
                break;

            case btn_34Pot:
                // 3/4 POT, rounded to a multiple of 10
                temp = Game.Pot * 3 / 4;
                temp = temp - (temp % 10);

                if(CurrentBet == temp)
                {
                    confirm = true;
                }
                else
                {
                    newBet = temp;
                }
                break;

            case btn_Pot:
                // POT
                if(CurrentBet == Game.Pot)
                {
                    confirm = true;
                }
                else
                {
                    newBet = Game.Pot;
                }
                break;

            case btn_Confirm:
                confirm = true;
                break;

            default:
                break;
            }
        }

        if(b == btn_Fold && !canComplete)
        {
            if(!SitOut)
            {
                CheckFold = !CheckFold;
            }
        }
        else if(b == btn_SitOut)
        {
            SwitchSitOut();
        }
        if(CheckFold && canComplete)
        {
            betComplete = canComplete;
            if(Game.Players[player].CanCheck)
            {
                Game.Players[player].Action = ICON_CHECKED;
            }
            else
            {
                newBet = 0;
                Fold(ThisPlayer);
            }

            if(Mode == gm_Standalone)
            {
                CheckFold = false;
            }
        }
        if(b == btn_Fold && !Game.Players[ThisPlayer].Folded)
        {
            DisplayCheckBox(BOTTOM, 6, 16, CheckFold);
        }

        if(b == btn_Minus)
        {
            newBet -= Game.Blind;
        }
        else if(b == btn_Plus)
        {
            if(newBet >= Game.MinBet + Game.LastRaise)
            {
                newBet += Game.Blind;
            }
            else
            {
                newBet = Game.MinBet + Game.LastRaise;
            }

            if(newBet > AllInCount(ThisPlayer))
            {
                newBet = AllInCount(ThisPlayer);
            }
        }
        else if(b == btn_NumPad)
        {
            // Number pad?
            x = (touch.px - 152) / 16;
            y = (touch.py - 80) / 16;

            if(x > 2 || y > 3)
            {
                return false;
            }

            value = KeypadValues[x + (3 * y)];

            if(value == -2)
            {
                // Clr
                newBet = 0;
            }
            else if(value == -1)
            {
                // Backspace
                newBet /= 10;
            }
            else
            {
                newBet = newBet * 10 + value;
            }
        }
    }

    if(confirm & canComplete)
    {
        // Bet confirmed (unless it's invalid)
        betComplete = ConfirmBet(newBet, player);
    }

    if(betComplete || newBet < 0)
    {
        newBet = 0;
    }

    if(newBet <= AllInCount(player))
    {
        CurrentBet = newBet;
        if(!betComplete)
        {
            if(CurrentBet > Game.MinBet)
            {
                DisplayBetOptions(ThisPlayer, Game.MinBet, Game.LastRaise, CurrentBet, true);
            }
            else if(!Game.Players[player].Folded)
            {
                DisplayBetOptions(ThisPlayer, Game.MinBet, Game.LastRaise, CurrentBet);
            }
        }
    }

    DisplayCurrentBet(CurrentBet, player);

    return betComplete;
}

bool ReadBet(int& CurrentBet, int& betStartTime)
{
    int curTime;
    int timeLeft;
    bool complete = false;

    complete = ConvertTouchToBet(ThisPlayer, CurrentBet);
    if(!complete)
    {
        curTime = TimeInSeconds();
        timeLeft = betStartTime + BET_TIME - curTime;
        if(timeLeft < 0)
        {
            if(Game.Players[Game.ActionOnPlayer].TimeBank > 0)
            {
                if(timeLeft < -1)
                {
                    Game.Players[Game.ActionOnPlayer].TimeBank--;
                    betStartTime++;
                }

                if(Game.ActionOnPlayer == ThisPlayer)
                {
                    Inverse = true;
                    DisplayMessage("Using Time Bank!");
                }
                else
                {
                    DisplayMessage("%s is using time bank", Game.Players[Game.ActionOnPlayer].Name);
                }
                prints(BOTTOM, 29, 22, "%2ds", Game.Players[Game.ActionOnPlayer].TimeBank);
                Inverse = false;
            }
            else
            {
                if(Game.ActionOnPlayer == ThisPlayer)
                {
                    // Timed out.
                    ClearMessage();
                    CurrentBet = 0;
                    if(Game.Players[ThisPlayer].CanCheck)
                    {
                        complete = true;
                        Game.Players[ThisPlayer].Action = ICON_CHECKED;
                    }
                    else
                    {
                        Fold(ThisPlayer);
                        complete = true;
                    }
                    SwitchSitOut();
                }
                else
                {
                    // TODO: Let next player sit this player out.
                }
            }
        }
        else
        {
            if(Game.ActionOnPlayer == ThisPlayer)
            {
                Inverse = true;
            }
            prints(BOTTOM, 29, 22, "%2ds", timeLeft);
            Inverse = false;
        }
    }
    DisplayPot();

    return complete;
}

int GetRank(int card)
{
    return ((card >> 8) & 0xF);
}

int GetSuit(int card)
{
    int suit;

    if ( card & CLUB )
        suit = 0;
    else if ( card & DIAMOND )
        suit = 1;
    else if ( card & 0x2000 )
        suit = 2;
    else
        suit = 3;

    return suit;
}

void DisplayHandOdds(int numCards)
{
    int f;

    if(!numCards)
    {
        DisplayMessage("Calculating Odds...");
    }

    if(numCards == 5)
    {
        for(f = 0 ; f < Game.MaxPlayers ; f++)
        {
            if(Game.Players[f].Cards[0] != -1 && !Game.Players[f].Folded)
            {
                DisplayOdds(f, -1);
            }
        }
        return;
    }

    InitializeForOdds();
    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        if(Game.Players[f].Cards[0] != -1)
        {
            if(Game.Players[f].Folded)
            {
                for(int g = 0 ; g < 2 ; g++)
                {
                    KillCard(GetRank(Game.Players[f].Cards[g]), GetSuit(Game.Players[f].Cards[g]));
                }
            }
            else
            {
                SetHoleCards(GetRank(Game.Players[f].Cards[0]), GetSuit(Game.Players[f].Cards[0]),
                             GetRank(Game.Players[f].Cards[1]), GetSuit(Game.Players[f].Cards[1]));
            }
        }
    }

    for(f = 0 ; f < numCards ; f++)
    {
        SetBoardCard(GetRank(Game.Board[f]), GetSuit(Game.Board[f]));
    }

    CalculateHandOdds();

    // Display results
    int result = 0;
    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        if(Game.Players[f].Cards[0] != -1 && !Game.Players[f].Folded)
        {
            DisplayOdds(f, Results[result++]);
        }
    }
}

void DisplayCommunityCards(int numCards, int screen)
{
    ConvertHand(Game.Board, numCards, CommunityCards);

    if(screen == TOP)
    {
        prints(TOP, 6, 7 + (Game.MaxPlayers == MAX_PLAYERS ? 4: 0), "%s", CommunityCards);
    }
    else
    {
        prints(BOTTOM, 12, 4, "%s", CommunityCards);
    }
}

void ShowCommunityCards(int numCards, bool showDown = false)
{
    if(Game.AllIn || showDown)
    {
        DisplayCommunityCards(numCards, TOP);
    }
    else
    {
        DisplayCommunityCards(numCards, BOTTOM);
        if(numCards > 2)
        {
            Game.ActionOnPlayer = Game.ButtonPos;
            NextPlayer();
        }
    }
}

void ClearBets(void)
{
    int f;

    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        Game.Players[f].TotalBet += Game.Players[f].Bet;
        Game.Players[f].Bet = 0;
        Game.Players[f].CanCheck = true;
        Game.Players[f].BigBlind = false;
        DisplayPlayer(f, false);
        DisplayBet(f, 0);
    }
    Game.MinBet = Game.Blind;
    Game.LastRaise = 0;
    Game.LastToAct = Game.ButtonPos;

    if(!Game.AllIn)
    {
        if(Game.Players[Game.ButtonPos].Folded || Game.Players[Game.ButtonPos].Chips == 0)
        {
            Game.LastToAct = FindLastToAct(Game.LastToAct);
        }
    }
}

void ClearActions(void)
{
    int f;

    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        Game.Players[f].Action = ' ';
        DisplayAction(f, true);
    }
}

void SetAllIn(void)
{
    Game.AllIn = true;
    ClearRows(BOTTOM, 0, 19);

    ClearActions();

    // Flip over cards
    int f;
    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        DisplayBet(f, 0);
        DisplayPlayer(f, false);
        DisplayCards(f, false);
    }

    DisplayCommunityCards(Game.CardsShowing, TOP);
}

void ReturnUncalledBets(void)
{
    // Uncalled bet is where there is a *single* player who has bet more
    // than any other player.
    int playersNotFolded = 0;
    int highBet = -1;
    int nextBet = -1;
    int highBetPos = -1;
    int highBetCount = 0;
    int f;

    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        if(!Game.Players[f].Folded && Game.Players[f].Bet > 0)
        {
            playersNotFolded++;
            if(Game.Players[f].Bet > highBet || highBet == -1)
            {
                nextBet = highBet;
                highBet = Game.Players[f].Bet;
                highBetPos = f;
                highBetCount = 1;
            }
            else if(Game.Players[f].Bet == highBet)
            {
                highBetCount++;
                // No need to update highBetPos, we no longer care
                // because there's more than one bet at this value.
            }
            else
            {
                if(Game.Players[f].Bet > nextBet || nextBet == -1)
                {
                    nextBet = Game.Players[f].Bet;
                }
            }
        }
    }

    if(highBetCount == 1 && playersNotFolded > 1)
    {
        Game.Players[highBetPos].Bet -= (highBet - nextBet);
        Game.Players[highBetPos].Chips += (highBet - nextBet);
        Game.Pot -= (highBet - nextBet);
        DisplayPot();
    }
    else if(highBetCount == 1)
    {
        int extra = Game.LastRaise;

        Game.Players[highBetPos].Bet -= extra;
        Game.Players[highBetPos].Chips += extra;
        Game.Pot -= extra;
        DisplayPlayer(highBetPos, true);
        DisplayPot();
    }
}

void BettingRound(void )
{
    GameState initialState = Game.State;
    int f;
    int currentBet = 0;
    int last = -1;
    int betStartTime;

    CheckFold = SitOut;
    if(!Game.AllIn)
    {
        while(!Game.AllIn)
        {
            if(last != Game.ActionOnPlayer)
            {
                last = Game.ActionOnPlayer;

                betStartTime = TimeInSeconds();
                DisplayPlayer(Game.ActionOnPlayer, true);

                if(Mode == gm_Standalone)
                {
                    ThisPlayer = Game.ActionOnPlayer;
                    currentBet = 0;
                }

                if(!Game.Players[ThisPlayer].Folded)
                {
                    DisplayBetOptions(ThisPlayer, Game.MinBet, Game.LastRaise, currentBet);
                }

                if(Game.ActionOnPlayer == ThisPlayer)
                {
                    if(Mode != gm_Standalone)
                    {
                        Beep();
                    }
                    Inverse = true;
                }
                DisplayMessage("Action is on %s", (Game.ActionOnPlayer == ThisPlayer ? "you" : Game.Players[Game.ActionOnPlayer].Name));
                Inverse = false;
            }

            if(ReadBet(currentBet, betStartTime))
            {
                // More than 1 player left in hand?
                // Are we All In?
                int playersRemaining = 0;
                int playersNotAllIn = 0;
                for(f = 0 ; f < Game.MaxPlayers ; f++)
                {
                    if(!Game.Players[f].Folded)
                    {
                        playersRemaining++;
                        if(Game.Players[f].Chips > 0)
                        {
                            playersNotAllIn++;
                        }
                    }
                }
                if(playersRemaining < 2)
                {
                    Game.Showdown = false;
                    Game.State = gs_Showdown;
                    break;
                }
                if(playersNotAllIn < 1)
                {
                    Game.AllIn = true;
                    break;
                }

                // Last to act has acted?
                if(Game.ActionOnPlayer == Game.LastToAct)
                {
                    UpdateScreens();
                    break;
                }

                NextPlayer();
                Game.Players[Game.ActionOnPlayer].Action = ' ';
                SendGameUpdate();
            }

            WaitForVBlank();
            if(Game.State != initialState)
            {
                return;
            }
        }

        // Account for case where only one player in the hand has chips left
        // (i.e. everyone else is all in).
        int playersWithChips = 0;
        for(f = 0 ; f < Game.MaxPlayers ; f++)
        {
            if(!Game.Players[f].Folded && Game.Players[f].Chips > 0)
            {
                playersWithChips++;
            }
        }

        if(playersWithChips == 1 && Game.State != gs_Showdown)
        {
            Game.AllIn = true;
        }

        ReturnUncalledBets();
        ClearBets();

        if(Game.AllIn)
        {
            SetAllIn();
        }
    }

    switch(Game.State)
    {
    case gs_PreFlopBetting:
        Game.State = gs_RunFlop;
        break;

    case gs_PostFlopBetting:
        Game.State = gs_RunTurn;
        break;

    case gs_PostTurnBetting:
        Game.State = gs_RunRiver;
        break;

    case gs_PostRiverBetting:
        Game.State = gs_Showdown;
        break;

    default:
        break;
    }
    SendGameUpdate();
}

void DealForSeats(void)
{
	int seats[MAX_PLAYERS] = {-1, -1, -1, -1, -1, -1, -1, -1};
    int seat;
    int seated = 0;

    while(seated != Game.TotPlayers)
    {
        seat = rand() % Game.TotPlayers;
        if(seats[seat] == -1)
        {
            seats[seat] = seated++;
        }
    }

    for(seat = 0; seat < Game.TotPlayers; seat++)
    {
        strcpy(Game.Players[seat].Name, PlayerNames[seats[seat]]);
        Game.Players[seat].DSCRC = CRCs[seats[seat]];
    }
}

void PreparePlayer(int player)
{
    Game.Players[player].Chips = Game.StartingChips;
    Game.Players[player].SittingIn = true;
    Game.Players[player].SitOutHands = 0;
    Game.Players[player].TimeBank = TIME_BANK;
    Game.Players[player].RabbitHunts = 1;
    Game.Players[player].Folded = true; // Will be reset at the start of each hand.
    Game.Players[player].Action = ' ';
    Game.Players[player].Bet = 0;
}

void InitTourney(void)
{
    int f;

    Game.StartingChips = 1500;
    Game.Blind = 20;
    Game.ButtonPos = 0;
    Game.Pot = 0;
    Game.CardsShowing = 0;
    Game.LevelStartTime = TimeInSeconds();
    Game.State = gs_NewHand;

    for(f = 0 ; f < Game.TotPlayers ; f++)
    {
        PreparePlayer(f);
    }
    for(f = Game.TotPlayers ; f < MAX_PLAYERS ; f++)
    {
        Game.Players[f].Name[0] = '\0';
        Game.Players[f].Chips = 0;
        Game.Players[f].Folded = true;
        Game.Players[f].SittingIn = false;
        Game.Players[f].Action = ' ';
        Game.Players[f].Bet = 0;
    }

    DealForSeats();
    TakeSeat();
    SendGameUpdate();
}

void SaveGame(void)
{
    FILE* outf = fopen("fat1:/ndsPoker.dat","w");

    if(outf)
    {
        Game.CurrentTime = TimeInSeconds();
        fwrite(&Mode, 1, sizeof(Mode), outf);
        fwrite(&Game, 1, sizeof(Game), outf);
        fclose(outf);
    }
}

void LoadGame(void)
{
    FILE *inf = fopen("fat1:/ndsPoker.dat","r");

    if(inf)
    {
        fread(&Mode, 1, sizeof(Mode), inf);
        fread(&Game, 1, sizeof(Game), inf);
        Game.LevelStartTime = TimeInSeconds() - (Game.CurrentTime - Game.LevelStartTime);
        fclose(inf);

        if(Mode == gm_Networked)
        {
            SetupWifi();
        }
        SendGameUpdate();
    }
}

void ShowDown(void)
{
    int winners[MAX_PLAYERS];
    int winnings[MAX_PLAYERS];
    bool shown[MAX_PLAYERS];
    int totWinners = 0;
    int score;
    int msgy = 0;
    int f;
    int newPot;
    char boardStr[32];
    char rabbitStr[12];
    char holeCards[32];

    ReturnUncalledBets();

    for(f = 0 ; f < Game.TotPlayers ; f++)
    {
        DisplayBet(f, 0);
    }

    DisplayBetOptions(-1, 0, 0, 0, false);
    if(!Game.AllIn)
    {
        HighlightAllPlayers(false);
    }
    ClearMessage();
    if(Game.RabbitHunt)
    {
        ConvertHand(Game.Board + 4, 1, rabbitStr);
        Inverse = true;
        prints(BOTTOM, 28, 4, "%s", rabbitStr);
        Inverse = false;
        Pause(60);
    }
    Pause(90);
    ClearActions();
    if(Game.Showdown)
    {
        Pause(60 + (Game.AllIn ? 60 : 0));
    }

    Cls(BOTTOM);

    if(Game.Raiser == -1)
    {
        Game.Raiser = Game.ActionOnPlayer;
    }

    for(f = 0 ; f < MAX_PLAYERS ; f++)
    {
        winnings[f] = 0;
        shown[f] = false;
    }

    if(Game.Showdown)
    {
        ConvertHand(Game.Board, 5, boardStr);
        rabbitStr[0] = '\0';
        ShowCommunityCards(5, true);

        do
        {
            Game.ActionOnPlayer = Game.Raiser;

            // Work out the highest and next highest bet.
            // There will always be (at least) two players with an equal bet until none are left.
            int highBet = -1;
            int nextBet = -1;
            int highBetCount = 0;

            totWinners = 0;

            for(f = 0 ; f < Game.MaxPlayers ; f++)
            {
                if(Game.Players[f].TotalBet > 0)
                {
                    if(Game.Players[f].TotalBet > highBet || highBet == -1)
                    {
                        nextBet = highBet;
                        highBet = Game.Players[f].TotalBet;
                        highBetCount = 1;
                    }
                    else if(Game.Players[f].TotalBet == highBet)
                    {
                        highBetCount++;
                    }
                    else
                    {
                        if(Game.Players[f].TotalBet > nextBet || nextBet == -1)
                        {
                            nextBet = Game.Players[f].TotalBet;
                        }
                    }
                }
            }

            if(nextBet == -1)
            {
                nextBet = 0;
            }

            if(highBetCount)
            {
                int bestScore = -1;

                newPot = highBetCount * (highBet - nextBet);
                for(f = 0 ; f < Game.MaxPlayers; f++)
                {
                    if(Game.Players[Game.ActionOnPlayer].TotalBet == highBet)
                    {
                        Game.Players[Game.ActionOnPlayer].TotalBet -= (highBet - nextBet);

                        if(!Game.Players[Game.ActionOnPlayer].Folded)
                        {
                            char handValue[40];

                            score = TestHand(Game.Board, Game.Players[Game.ActionOnPlayer].Cards, handValue, (Game.Type != gt_Holdem));
                            if(NumCards == 2)
                            {
                                ConvertHand(Game.Players[Game.ActionOnPlayer].Cards, NumCards, holeCards);
                            }
                            else
                            {
                                ConvertHandSmall(Game.Players[Game.ActionOnPlayer].Cards, NumCards, holeCards);
                            }

                            if(bestScore == -1 || score <= bestScore)
                            {
                                if(score < bestScore)
                                {
                                    while(totWinners)
                                    {
                                        Fold(winners[--totWinners], true);
                                        RevealHoleCards(winners[totWinners], true);
                                    }
                                }
                                winners[totWinners++] = Game.ActionOnPlayer;

                                RevealHoleCards(Game.ActionOnPlayer);
                                bestScore = score;
                                if(!shown[Game.ActionOnPlayer])
                                {
                                    if(NumCards == 2)
                                    {
                                        prints(BOTTOM, 0, msgy, "%-8s-%s-%s", Game.Players[Game.ActionOnPlayer].Name, holeCards, handValue);
                                    }
                                    else
                                    {
                                        holeCards[5] = '\0';
                                        prints(BOTTOM, 0, msgy, "%-8s-%s-%s", Game.Players[Game.ActionOnPlayer].Name, holeCards, handValue);
                                        prints(BOTTOM, 9, msgy + 1, "%s", holeCards + 6);
                                    }
                                    shown[Game.ActionOnPlayer] = true;
                                    msgy += 2;
                                    if(!Game.AllIn)
                                    {
                                        Pause(60);
                                    }
                                }
                            }
                            else
                            {
                                Fold(Game.ActionOnPlayer, true);
                                RevealHoleCards(Game.ActionOnPlayer, true);
                                if(Game.AllIn)
                                {
                                    if(!shown[Game.ActionOnPlayer])
                                    {
                                        if(NumCards == 2)
                                        {
                                            prints(BOTTOM, 0, msgy, "%-8s-%s-%s", Game.Players[Game.ActionOnPlayer].Name, holeCards, handValue);
                                        }
                                        else
                                        {
                                            holeCards[5] = '\0';
                                            prints(BOTTOM, 0, msgy, "%-8s-%s-%s", Game.Players[Game.ActionOnPlayer].Name, holeCards, handValue);
                                            prints(BOTTOM, 9, msgy + 1, "%s", holeCards + 6);
                                        }
                                        shown[Game.ActionOnPlayer] = true;
                                        msgy += 2;
                                        if(!Game.AllIn)
                                        {
                                            Pause(60);
                                        }
                                    }
                                }
                                else
                                {
                                    if(!shown[Game.ActionOnPlayer])
                                    {
                                        prints(BOTTOM, 0, msgy, "%-8s mucks", Game.Players[Game.ActionOnPlayer].Name);
                                        shown[Game.ActionOnPlayer] = true;
                                        msgy += 2;
                                        if(!Game.AllIn)
                                        {
                                            Pause(60);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    Game.ActionOnPlayer = (Game.ActionOnPlayer + 1) % Game.MaxPlayers;
                }

                for(f = 0 ; f < totWinners ; f++)
                {
                    winnings[winners[f]] += (newPot / totWinners);
                }
            }
        } while (totWinners);
    }
    else
    {
        ConvertHand(Game.Board, Game.CardsShowing, boardStr);

        // Find out who won.
        for(f = 0 ; f < Game.MaxPlayers ; f++)
        {
            if(!Game.Players[f].Folded)
            {
                winnings[f] = Game.Pot;
                totWinners = 1;
                break;
            }
        }
    }

    // Give the chips to the winner(s).
    // Any chips that couldn't be split will be left in for the next hand.
    if(totWinners < 3)
    {
        msgy++;
    }

    for(f = 0 ; f < Game.MaxPlayers ; f++)
    {
        if(winnings[f])
        {
            Game.Players[f].Chips += winnings[f];
            Game.Pot -= winnings[f];
            DisplayPlayer(f, true);
            prints(BOTTOM, 0, msgy, "%s wins %d", Game.Players[f].Name, winnings[f]);
            msgy += 2;
        }
        else
        {
            DisplayPlayer(f, false);
        }
    }

    prints(BOTTOM, 0, 22, "%s", boardStr);

    if(Game.RabbitHunt)
    {
        Inverse = 1;
        prints(BOTTOM, strlen(boardStr) + 1, 22, "%s", rabbitStr);
        Inverse = 0;
    }

    if(Mode != gm_Standalone && Game.Players[ThisPlayer].Cards[0] != -1)
    {
        if(NumCards == 2)
        {
            ConvertHand(Game.Players[ThisPlayer].Cards, NumCards, holeCards);
        }
        else
        {
            ConvertHandSmall(Game.Players[ThisPlayer].Cards, NumCards, holeCards);
        }
        if(NumCards == 2)
        {
            prints(BOTTOM, 32 - strlen(holeCards), 22, "%s", holeCards);
        }
        else
        {
            holeCards[5] = '\0';
            prints(BOTTOM, 32 - strlen(holeCards), 22, "%s", holeCards);
            prints(BOTTOM, 32 - strlen(holeCards), 23, "%s", holeCards + 6);
        }
    }

    // Copy the screen to the 2nd layer in case anyone wants to look back.
    dmaCopy(subMap, subMap2, 24 * 32 * 2);
    memcpy(OldHands[OldHandPtr], subMap, 24 * 32 * 2);
    OldHandPtr = (OldHandPtr + 1) % MAX_OLD_HANDS;

    if(CountPlayers(true) < 2)
    {
        Game.State = gs_Complete;
        SendGameUpdate();
        for(f = 300 ; f > 0 ; f--)
        {
            int pressed = KeyPressed();
            if((pressed & KEY_TOUCH) || (pressed & KEY_A))
            {
                break;
            }
            WaitForVBlank();
		}
	}
    else
    {
        Game.State = gs_WaitingForRebuy;
    }

    if((Mode == gm_Standalone || ThisPlayer == Game.ButtonPos) && Game.State != gs_Complete)
    {
        for(f = 180 ; f > 0 ; f--)
        {
            if(f % 60 == 0)
            {
                Inverse = true;
				prints(TOP, 1, 7 + (Game.MaxPlayers == 8 ? 4: 0), "Touch Screen For Next Hand (%d)", f / 60);
                Inverse = false;
            }

            int pressed = KeyPressed();
            if((pressed & KEY_TOUCH) || (pressed & KEY_A))
            {
                break;
            }
            WaitForVBlank();
        }
        Game.State = gs_Rebuy;
        SendGameUpdate();
    }
}

void Rebuy(void)
{
    bool rebuy = false;

    for(int f = 0 ; f < Game.TotPlayers; f++)
    {
        DisplayPlayer(f, false);
    }

    for(int f = 0 ; f < Game.TotPlayers; f++)
    {
        if(Game.Players[f].SittingIn && Game.Players[f].Chips == 0 && !Game.Players[f].SitOutHands)
        {
            Game.CardsShowing = 0; // Otherwise the cards will be shown again after the rebuys are complete.
            rebuy = true;
            if(f == ThisPlayer || Mode == gm_Standalone)
            {
                Pause(15);
                DisplayPlayer(f, true);

                prints(TOP, 0, 7 + (Game.MaxPlayers == 8 ? 4: 0), "                                ");
                Inverse = true;
        		prints(TOP, 13, 7 + (Game.MaxPlayers == 8 ? 4: 0), "Rebuy?");
                Inverse = false;

                // This player's turn to rebuy (or not).
                int rebuyOption = GetMenuOption(2, 0, "Rebuy", "Quit");

                if(rebuyOption == 0)
                {
                    Game.Players[f].SitOutHands = 10;
                    SendGameUpdate();
                    break;
                }
                else
                {
                    Game.Players[f].SittingIn = false;
                    SendGameUpdate();
                    break;
                }
            }
            else
            {
                prints(TOP, 0, 7 + (Game.MaxPlayers == 8 ? 4: 0), "                                ");
                Inverse = true;
        		prints(TOP, 6, 7 + (Game.MaxPlayers == 8 ? 4: 0), "Waiting For Rebuy(s)");
                Inverse = false;
            }
            break;
        }
    }
    if(!rebuy)
    {
        Game.State = gs_NewHand;
        SaveGame();
    }
}

void StartHand()
{
    int f, g;
    int blindAmount;
    bool nextToAct;
    int totPlayers;
    int pos;
    int DeckPos = 0;

    shuffle_deck(Deck);
    MoveButton();
    pos = Game.ButtonPos;

    do {
        // Anyone bought back in?
        for(f = 0 ; f < MAX_PLAYERS ; f++)
        {
            if(Game.Players[f].SitOutHands)
            {
                Game.Players[f].SitOutHands--;
                if(!Game.Players[f].SitOutHands)
                {
                    Game.Players[f].Chips = 1000;
                }
            }
        }
        totPlayers = CountPlayers();

        // If there's only 1 player with chips, skip hands until someone rebuys.
    } while(totPlayers == 1);

    while(TimeLeft() < 0)
    {
        RaiseBlinds();
    }

    for(f = 0 ; f < MAX_PLAYERS ; f++)
    {
        for(g = 0 ; g < 4 ; g++)
        {
            Game.Players[f].Cards[g] = -1;
        }
    }

    for(f = 0 ; f < totPlayers ; f++)
    {
        nextToAct = false;
        blindAmount = 0;
        for(g = 0 ; g < NumCards ; g++)
        {
            Game.Players[pos].Cards[g] = NextCard(DeckPos);
        }
        Game.Players[pos].Folded = (Game.Players[pos].Chips == 0);
        Game.Players[pos].CanCheck = false;
        Game.Players[pos].Bet = 0;
        Game.Players[pos].TotalBet = 0;

        if(f == 0)
        {
            if(totPlayers == 2)
            {
                // Dealer posts Small Blind heads up.
                blindAmount = Game.Blind / 2;

                // And is next to act.
                nextToAct = true;
            }
            else if(totPlayers == 3)
            {
                // 3-handed, the dealer is UTG.
                nextToAct = true;
            }
        }
        else if(f == 1)
        {
            if(totPlayers == 2)
            {
                // Heads up, next after button is Big Blind.
                blindAmount = Game.Blind;
                Game.LastToAct = pos;
            }
            else
            {
                blindAmount = Game.Blind / 2;
            }
        }
        else if(f == 2)
        {
            blindAmount = Game.Blind;
            Game.LastToAct = pos;
        }
        else if(f == 3)
        {
            nextToAct = true;
        }

        // Take the blinds from the players.
        if(blindAmount)
        {
            if(blindAmount == Game.Blind)
            {
                Game.Players[pos].BigBlind = true;
                Game.Players[pos].CanCheck = true;
            }

            // Player might not have enough chips for the blind.
            if(blindAmount > Game.Players[pos].Chips)
            {
                blindAmount = Game.Players[pos].Chips;
            }

            Game.Players[pos].Chips -= blindAmount;
            Game.Players[pos].Bet = blindAmount;
            Game.Pot += blindAmount;
        }

        if(nextToAct)
        {
            Game.ActionOnPlayer = pos;
        }

        while(1)
        {
            pos = (pos + 1) % Game.MaxPlayers;
            if(Game.Players[pos].Chips > 0)
            {
                break;
            }
        }
    }

    // Decrement starting chips by 1/2 a blind and round up to a multiple of 5.
    Game.StartingChips -= (Game.Blind / 2);
    if(Game.StartingChips % 5)
    {
        Game.StartingChips += 5 - (Game.StartingChips % 5);
    }
    if(Game.StartingChips < 1000)
    {
        Game.StartingChips = 1000;
    }

    // Select all 5 community cards.
    for(f = 0 ; f < 5 ; f++)
    {
        Game.Board[f] = NextCard(DeckPos);
    }
    CommunityCards[0] = '\0';

    Game.MinBet = Game.Blind;
    Game.LastRaise = Game.Blind;
    Game.Raiser = -1;
    Game.AllIn = false;
    Game.State = gs_PreFlopBetting;
    Game.Showdown = true;
    Game.CardsShowing = 0;
    Game.RabbitHunt = false;

    SendGameUpdate();

    if(Mode == gm_Standalone)
    {
        ThisPlayer = Game.ActionOnPlayer;
    }
}

void FlopCards(int numCards, const char *message, GameState newState)
{
    int f;

    if(Game.AllIn && Game.Type == gt_Holdem && (Game.CardsShowing == 0 || Game.CardsShowing > 2))
    {
        DisplayHandOdds(Game.CardsShowing);
    }

    DisplayBetOptions(-1, 0, 0, 0, false);
    HighlightAllPlayers(false);
    DisplayMessage(message);
    Pause(120 + (Game.AllIn ? 60 : 0));
    
    for(f = (numCards == 3 ? 1 : numCards) ; f <= numCards ; f++)
    {
        Pause(45);
        ShowCommunityCards(f);
    }
    ClearActions();
    ClearMessage();
    Game.CardsShowing = numCards;
    Game.State = newState;
}

void TakeSeat(void)
{
    int f;

    // Find out where we're sitting.
    for(f = 0 ; f < Game.TotPlayers ; f++)
    {
        if(!strcmp(PlayerName, Game.Players[f].Name))
        {
            ThisPlayer = f;

            // Is someone trying to join game using someone else's name?
            if(Mode == gm_Networked && Game.Players[f].DSCRC != ThisDS)
            {
                Cls(TOP);
                Cls(BOTTOM);
                prints(TOP, 0, 0, "Nice try");
                while(1)
                {
                    swiWaitForVBlank();
                }
            }
            break;
        }
    }
}

void PlayGame(void)
{
	NumCards = (Game.Type == gt_Holdem ? 2 : 4);
	Game.MaxPlayers = (Game.TotPlayers > 6  ? MAX_PLAYERS : 6);
	if(Game.MaxPlayers == MAX_PLAYERS)
	{
		Seats = (SEAT *)&EightSeats;
	}
	else
	{
		Seats = (SEAT *)&SixSeats;
	}

	if(Game.State != gs_Setup)
    {
        UpdateScreens();
    }

    while(Game.State != gs_Complete)
    {
		if(Game.State != gs_Setup)
		{
		    WaitForVBlank();
		}

        switch(Game.State)
        {
        case gs_Setup:
            InitTourney();
            break;

        case gs_NewHand:
            if(Mode == gm_Standalone || ThisPlayer == Game.ButtonPos)
            {
                StartHand();
            }
            else
            {
                shuffle_deck(Deck);
            }
            break;

        case gs_PreFlopBetting:
            Cls(TOP);
            Cls(BOTTOM);
            HoleCardsShowing = true;
            UpdateScreens();

            BettingRound();
            break;

        case gs_RunFlop:
            // Flop
            FlopCards(3, "And now for the flop..", gs_PostFlopBetting);
            break;

        case gs_PostFlopBetting:
            BettingRound();
            break;

        case gs_RunTurn:
            // Turn
            FlopCards(4, "The turn..", gs_PostTurnBetting);
            break;

        case gs_PostTurnBetting:
            BettingRound();
            break;

        case gs_RunRiver:
            // River
            FlopCards(5, "The river..", gs_PostRiverBetting);
            break;

        case gs_PostRiverBetting:
            BettingRound();
            break;

        case gs_Showdown:
            ShowDown();
            break;

        case gs_WaitingForRebuy:
            // Nothing to do until state changes to gs_Rebuy
            break;

        case gs_Rebuy:
            Rebuy();
            break;

        default:
            break;
        }
    }
}

static void ErrorHandler()
{
    Cls(BOTTOM);
    prints(BOTTOM, 0, 0, "Oops, something went pear shaped");

    while(1)
    {
        swiWaitForVBlank();
    }
}

int main(void)
{
    setExceptionHandler(ErrorHandler);
    keysSetRepeat(50, 8);

    int f, defaultOption;

    for(f = 0 ; f < MAX_PLAYERS ; f++)
    {
        PlayerNames[f] = (char *)malloc(MAX_NAME_LEN);
    }

    // First, wait for a VBlank - seems things are happier for this.
    WaitForVBlank();
    WaitForVBlank();

    fatInitDefault();
    InitScreen();

    // Get name of DS
    char DSName[40];
    char *pos = DSName;
    for(f = 0 ; f < PersonalData->nameLen ; f++)
    {
        *pos++ = PersonalData->name[f] & 255;
    }
    ThisDS = CalculateCRC(DSName, strlen(DSName));

    PlayerName[0] = '\0';
    FILE *inf = fopen("fat1:/ndsPokerPlayer.dat", "r");
    if(inf)
    {
        fscanf(inf, "%s", PlayerName);
        fclose(inf);
        defaultOption = 1;
    }
    else
    {
        defaultOption = 0;
    }

    init_deck( Deck );
    Randomize();

    MinsPerLevel = 10;

    while(1)
    {
        // Make sure the summary screen isn't being displayed.
        bgHide(bg1);
        bgShow(bg0);

		Mode = gm_Menu;
        Cls(TOP);
        Mode = (GameMode)GetMenuOption(4, defaultOption, "Standalone", "Networked", "Load Saved Game", "Set Name");

        ThisPlayer = -1;

        switch(Mode)
        {
            case gm_Standalone:
                Cls(TOP);
                Game.Type = (GameType)GetMenuOption(2, 0, "Holdem", "Omaha Hi");
                strcpy(PlayerNames[0],"PETE");
                strcpy(PlayerNames[1],"JOHN");
                strcpy(PlayerNames[2],"LEO");
                strcpy(PlayerNames[3],"FRED");
                strcpy(PlayerNames[4],"AJ");
                strcpy(PlayerNames[5],"CHARLES");
                strcpy(PlayerNames[6],"RAVI");
                strcpy(PlayerNames[7],"ANDREW");
				Game.TotPlayers = (Game.Type == gt_Omaha ? 6 : MAX_PLAYERS);
                Game.State = gs_Setup;
                PlayGame();
                break;

            case gm_Networked:
                Game.Type = gt_Holdem;
                if(!PlayerName[0])
                {
                    GetPlayerName(PlayerName);
                }
                SetupWifi();
                FindPlayers(PlayerName);
                PlayGame();
                break;

            case gm_Load:
                LoadGame();
                PlayGame();
                break;

            case gm_SetName:
                GetPlayerName(PlayerName);
                break;

            case gm_Menu:
                break;
        }
    }
    return 0;
}
